package com.af.service;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author : zhenyun.su
 * @comment : 日志管理，动态调整日志级别， 依赖于logback框架
 * @since : 2020-8-6
 * level可取值： ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF
 * 参考： ch.qos.logback.classic.Level;
 * 使用说明：
 *     @Bean
 *     public SzyLoggingService szyLoggingService(){
 *         return new SzyLoggingService();
 *     }
 * 来源于： 1-core 模块 com.szy.common.logging.SzyLoggingService
 */

public class AfLoggingService {
    public static final Level defaultLevel = Level.INFO;
    public static final String NULL_LEVEL = "None";

    /**
     * @comment : 按包名获取logger
     */
    public Logger getLogger(String packageName) throws Exception {
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
        Logger logger = loggerContext.getLogger(packageName);
        if (ObjectUtils.isEmpty(logger)) {
            throw new Exception(String.format("logger %s is not exist", packageName));
        }
        return logger;
    }

    /**
     * @comment : 按包名，更新对应logger的日志级别
     */
    public void updateLoggerLevel(String packageName, String newLevel) throws Exception {
        String oldLevelStr = "none";
        try {
            Logger logger = getLogger(packageName);
            if (logger.getLevel() != null) {
                oldLevelStr = logger.getLevel().levelStr;
            }
            logger.setLevel(Level.toLevel(newLevel, defaultLevel));
        } catch (Exception e) {
            throw new Exception(String.format("logger %s change level, %s to %s failed", packageName, oldLevelStr, newLevel));
        }
    }

    public String getLoggerLevel(String packageName) throws Exception {
        Logger logger = getLogger(packageName);
        if (logger.getLevel() != null) {
            return logger.getLevel().levelStr;
        }
        return NULL_LEVEL;
    }

    public List<Logger> getLoggerAll(String packageName) {
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
        List<Logger> loggerList = loggerContext.getLoggerList();
        if (StringUtils.isEmpty(packageName)) {
            return loggerList;
        }
        List<Logger> loggers = new ArrayList<>();
        for (Logger logger : loggerList) {
            if (logger.getName().indexOf(packageName) >= 0) {
                loggers.add(logger);
            }
        }

        return loggers;
    }

    /**
     * @comment : 按包名及子包，更新所有logger的日志级别
     */
    public void updateLoggerAllLevel(String packageName, String newLevel) throws Exception {
        try {
            List<Logger> loggerList = getLoggerAll(packageName);
            for (Logger logger : loggerList) {
                if (logger.getLevel() != null || logger.getName().equalsIgnoreCase(packageName)) {
                    logger.setLevel(Level.toLevel(newLevel, defaultLevel));
                }
            }
        } catch (Exception e) {
            throw new Exception(String.format("according to %s, update all logger level to %s failed", packageName, newLevel));
        }
    }

    public Map<String, String> getLoggerLevelAll(String packageName) throws Exception {
        List<Logger> loggerList = getLoggerAll(packageName);
        Map<String, String> map = new HashMap<>();
        try {
//            String res = loggerList.stream().map(Logger::getName).collect(Collectors.joining(","));
            for (Logger logger : loggerList) {
                if (logger.getName().contains("$")) {
                    continue;
                }
                String loggerName = logger.getName();
                if (logger.getLevel() == null) {
                    map.put(loggerName, NULL_LEVEL);
                } else {
                    map.put(loggerName, logger.getLevel().levelStr);
                }
            }
        } catch (Exception e) {
            throw new Exception(String.format("getLoggerLevelAll failed, according to %s", packageName));
        } finally {
            return map;
        }
    }

}
